<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="./src/wqx.js"></script>
    <style>
        #wqx {
            position: absolute;
            left: 16px;
            top: 50px;
            padding: 10px;
            border: 1px solid gray;
            background-color: #cfcfcf;
        }
        #lcd {
            background-color: #90B057;
        }
        #split {
            border-top: 2px solid gray;
            height: 0;
            margin: 5px 0;
        }
        #keypad {
            width: 376px;
            height: 160px;
            padding-top: 3px;
        }
        #keypad>div {
            height: 24px;
            margin-bottom: 3px;
        }
        .keypad_unit {
            width: 32px;
            height: 20px;
            border-radius: 3px;
            display: inline-block;
            background-color: rgb(213, 233, 205);
            border: 1px solid rgb(128, 208, 70);
            margin-right: 4px;
            -webkit-user-select: none;
            -moz-user-select: none;
            -o-user-select: none;
            cursor: pointer;
        }
        .keypad_unit:last-child {
            margin-right: 0;
        }
        .keypad_unit.pressed {
            background-color: rgb(192, 192, 192);
            border-color: black;
        }
        .keypad_unit_label {
            font-size: 12px;
            line-height: 20px;
            color: rgb(128, 208, 70);
            text-align: center;
            position: absolute;
            width: 32px;
            height: 20px;
            overflow: hidden;
        }
    </style>
</head>
<body>
<div id="controls">
    <button id="play_or_stop" disabled>play</button>
    <button id="reset" disabled>reset</button>
    <button id="upload" disabled title="upload flash file">upload</button>
    <button id="download" disabled title="download flash file">download</button>
    <button id="load">load</button>
</div>
<div id="wqx">
    <canvas id="lcd" width="376" height="160"></canvas>
    <div id="split"></div>
    <div id="keypad" tabindex="0"></div>
</div>
<script>
    var btn_play_or_stop = document.getElementById('play_or_stop');
    var btn_reset = document.getElementById('reset');
    var btn_load = document.getElementById('load');
    var btn_upload = document.getElementById('upload');
    var btn_download = document.getElementById('download');
    var lcd_canvas = document.getElementById('lcd');
    var keypad_div = document.getElementById('keypad');
    var wqx = new JsWqx(lcd_canvas);
    btn_load.onclick = function (){
        btn_load.setAttribute('disabled', 'disabled');
        var rom;
        var nor;
        function check(){
            if (rom && nor) {
                setTimeout(function (){
                    btn_play_or_stop.removeAttribute('disabled');
                    btn_reset.removeAttribute('disabled');
                    btn_upload.removeAttribute('disabled');
                    btn_download.removeAttribute('disabled');
                    btn_load.textContent = 'done';
                    wqx.init(rom, nor, lcd_canvas.getContext('2d'));
                    wqx.reset();
                });
            } else {
                btn_load.removeAttribute('disabled');
                btn_load.textContent = 'fail';
            }
        }
        function progress(i, p1, p2){
            btn_load.textContent = 'loading '+ i +'/2: '+ p1 +'/'+ p2;
        }
        var xhrRom = new XMLHttpRequest();
        xhrRom.open('GET', './refs/obj_lu.bin', true);
        xhrRom.responseType = 'arraybuffer';
        xhrRom.addEventListener('progress', function (evt){
            progress(1, evt.loaded, evt.total);
        });
        xhrRom.addEventListener('loadend', function (){
            rom = xhrRom.response;
            var xhrNor = new XMLHttpRequest();
            xhrNor.open('GET', './refs/nc1020.fls', true);
            xhrNor.responseType = 'arraybuffer';
            xhrNor.addEventListener('progress', function (evt){
                progress(2, evt.loaded, evt.total);
            });
            xhrNor.addEventListener('loadend', function (){
                nor = xhrNor.response;
                check();
            }, false);
            xhrNor.send();
        }, false);
        xhrRom.send();
    };

    btn_upload.onclick = function (){
        var file_input = document.createElement('input');
        file_input.setAttribute('type', 'file');
        file_input.addEventListener('change', function (){
            var file = file_input.files[0];
            var reader = new FileReader();
            reader.addEventListener('load', function (){
                wqx.setNorBuffer(reader.result);
                alert('upload done.');
                if (playing) {
                    wqx.reset();
                }
            });
            reader.readAsArrayBuffer(file);
        });
        file_input.click();
    };

    var last_blob_url;
    btn_download.onclick = function (){
        var file_a = document.createElement('a');
        file_a.setAttribute('target', '_blank');
        var blob = new Blob([wqx.getNorBuffer()], {
            type: 'application/octet-stream'
        });
        if (last_blob_url) {
            URL.revokeObjectURL(last_blob_url);
            last_blob_url = null;
        }
        var blob_url = URL.createObjectURL(blob);
        file_a.setAttribute('href', blob_url);
        file_a.click();
        last_blob_url = blob_url;
    };

    var playing = true;
    btn_play_or_stop.onclick = function (){
        if (playing) {
            btn_play_or_stop.textContent = 'stop';
            wqx.play();
        } else {
            btn_play_or_stop.textContent = 'play';
            wqx.stop();
        }
        playing = !playing;
    };
    btn_reset.onclick = function (){
        wqx.reset();
    };

    (function (){
        var KEY_CODE_MAP = new Array(0x100);
        KEY_CODE_MAP[0x74] = 0x0b;
        KEY_CODE_MAP[0x75] = 0x0c;
        KEY_CODE_MAP[0x76] = 0x0d;
        KEY_CODE_MAP[0x77] = 0x09;
        KEY_CODE_MAP[0x78] = 0x0a;
        KEY_CODE_MAP[0x79] = 0x08;
        KEY_CODE_MAP[0x7a] = 0x0e;
        KEY_CODE_MAP[0x7b] = 0x0f;
        KEY_CODE_MAP[0x70] = 0x10;
        KEY_CODE_MAP[0x71] = 0x11;
        KEY_CODE_MAP[0x72] = 0x12;
        KEY_CODE_MAP[0x73] = 0x13;
        KEY_CODE_MAP[0x4f] = 0x18;
        KEY_CODE_MAP[0x4c] = 0x19;
        KEY_CODE_MAP[0x26] = 0x1a;
        KEY_CODE_MAP[0x28] = 0x1b;
        KEY_CODE_MAP[0x50] = 0x1c;
        KEY_CODE_MAP[0x0d] = 0x1d;
        KEY_CODE_MAP[0x22] = 0x1e;
        KEY_CODE_MAP[0x27] = 0x1f;
        KEY_CODE_MAP[0x51] = 0x20;
        KEY_CODE_MAP[0x57] = 0x21;
        KEY_CODE_MAP[0x45] = 0x22;
        KEY_CODE_MAP[0x52] = 0x23;
        KEY_CODE_MAP[0x54] = 0x24;
        KEY_CODE_MAP[0x59] = 0x25;
        KEY_CODE_MAP[0x55] = 0x26;
        KEY_CODE_MAP[0x49] = 0x27;
        KEY_CODE_MAP[0x41] = 0x28;
        KEY_CODE_MAP[0x53] = 0x29;
        KEY_CODE_MAP[0x44] = 0x2a;
        KEY_CODE_MAP[0x46] = 0x2b;
        KEY_CODE_MAP[0x47] = 0x2c;
        KEY_CODE_MAP[0x48] = 0x2d;
        KEY_CODE_MAP[0x4a] = 0x2e;
        KEY_CODE_MAP[0x4b] = 0x2f;
        KEY_CODE_MAP[0x5a] = 0x30;
        KEY_CODE_MAP[0x58] = 0x31;
        KEY_CODE_MAP[0x43] = 0x32;
        KEY_CODE_MAP[0x56] = 0x33;
        KEY_CODE_MAP[0x42] = 0x34;
        KEY_CODE_MAP[0x4e] = 0x35;
        KEY_CODE_MAP[0x4d] = 0x36;
        KEY_CODE_MAP[0x21] = 0x37;
        KEY_CODE_MAP[0x09] = 0x38;
        KEY_CODE_MAP[0xe5] = 0x39;
        KEY_CODE_MAP[0x14] = 0x3a;
        KEY_CODE_MAP[0x1b] = 0x3b;
        KEY_CODE_MAP[0x30] = 0x3c;
        KEY_CODE_MAP[0xbe] = 0x3d;
        KEY_CODE_MAP[0xbb] = 0x3e;
        KEY_CODE_MAP[0x25] = 0x3f;
        // backspace
        KEY_CODE_MAP[0x08] = KEY_CODE_MAP[0x25];
        // 1 ~ 9
        KEY_CODE_MAP[0x31] = KEY_CODE_MAP[0x42];
        KEY_CODE_MAP[0x32] = KEY_CODE_MAP[0x4e];
        KEY_CODE_MAP[0x33] = KEY_CODE_MAP[0x4d];
        KEY_CODE_MAP[0x34] = KEY_CODE_MAP[0x47];
        KEY_CODE_MAP[0x35] = KEY_CODE_MAP[0x48];
        KEY_CODE_MAP[0x36] = KEY_CODE_MAP[0x4a];
        KEY_CODE_MAP[0x37] = KEY_CODE_MAP[0x54];
        KEY_CODE_MAP[0x38] = KEY_CODE_MAP[0x59];
        KEY_CODE_MAP[0x39] = KEY_CODE_MAP[0x55];

        var KEY_NAME_MAP = new Array(0x40);

        KEY_NAME_MAP[0x0B] = '英汉 (F5)^汉英';
        KEY_NAME_MAP[0x0C] = '名片 (F6)^通讯';
        KEY_NAME_MAP[0x0D] = '计算 (F7)^换算';
        KEY_NAME_MAP[0x0A] = '行程 (F8)^资料';
        KEY_NAME_MAP[0x09] = '测验 (F9)^游戏';
        KEY_NAME_MAP[0x08] = '其他 (F10)^时间';
        KEY_NAME_MAP[0x0E] = '网络 (F11)';
        KEY_NAME_MAP[0x0F] = '电源 (F12)';

        KEY_NAME_MAP[0x10] = 'F1';
        KEY_NAME_MAP[0x11] = 'F2';
        KEY_NAME_MAP[0x12] = 'F3';
        KEY_NAME_MAP[0x13] = 'F4';

        KEY_NAME_MAP[0x18] = 'O';
        KEY_NAME_MAP[0x19] = 'L';
        KEY_NAME_MAP[0x1A] = '⇧';
        KEY_NAME_MAP[0x1B] = '⇩';
        KEY_NAME_MAP[0x1C] = 'P';
        KEY_NAME_MAP[0x1D] = 'Enter';
        KEY_NAME_MAP[0x1E] = 'PgDn';
        KEY_NAME_MAP[0x1F] = '⇨';

        KEY_NAME_MAP[0x20] = 'Q';
        KEY_NAME_MAP[0x21] = 'W';
        KEY_NAME_MAP[0x22] = 'E';
        KEY_NAME_MAP[0x23] = 'R';
        KEY_NAME_MAP[0x24] = 'T /7';
        KEY_NAME_MAP[0x25] = 'Y /8';
        KEY_NAME_MAP[0x26] = 'U /9';
        KEY_NAME_MAP[0x27] = 'I';

        KEY_NAME_MAP[0x28] = 'A';
        KEY_NAME_MAP[0x29] = 'S';
        KEY_NAME_MAP[0x2A] = 'D';
        KEY_NAME_MAP[0x2B] = 'F';
        KEY_NAME_MAP[0x2C] = 'G /4';
        KEY_NAME_MAP[0x2D] = 'H /5';
        KEY_NAME_MAP[0x2E] = 'J /6';
        KEY_NAME_MAP[0x2F] = 'K';

        KEY_NAME_MAP[0x30] = 'Z';
        KEY_NAME_MAP[0x31] = 'X';
        KEY_NAME_MAP[0x32] = 'C';
        KEY_NAME_MAP[0x33] = 'V';
        KEY_NAME_MAP[0x34] = 'B /1';
        KEY_NAME_MAP[0x35] = 'N /2';
        KEY_NAME_MAP[0x36] = 'M /3';
        KEY_NAME_MAP[0x37] = 'PgUp';

        KEY_NAME_MAP[0x38] = '求助 (Tab)';
        KEY_NAME_MAP[0x39] = '中英 (Shift)';
        KEY_NAME_MAP[0x3A] = 'CapsLk';
        KEY_NAME_MAP[0x3B] = '退出 (Esc)';
        KEY_NAME_MAP[0x3C] = '0';
        KEY_NAME_MAP[0x3D] = '.';
        KEY_NAME_MAP[0x3E] = '=';
        KEY_NAME_MAP[0x3F] = '⇦';

        // 0x02 红外线.
        var KEYPAD = [
                [0x10, 0x11, 0x12, 0x13, null, null, null, null, null, 0x0F],
                [null, null, null, 0x0B, 0x0C, 0x0D, 0x0A, 0x09, 0x08, 0x0E],
                [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x1C],
                [0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x19, 0x1D],
                [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x1A, 0x1E],
                [0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x1B, 0x1F]
        ];

        var buff = [];
        for (var r = 0; r<KEYPAD.length; r++){
            var row = KEYPAD[r];
            buff.push('<div>');
            for (var c=0; c<row.length; c++) {
                var cell = row[c];
                if (cell != null) {
                    buff.push('<div class="keypad_unit" data-key="0x');
                    buff.push(('00'+cell.toString(16)).slice(-2));
                    buff.push('" title="');
                    buff.push(KEY_NAME_MAP[cell]);
                    buff.push('"><div class="keypad_unit_label">');
                    buff.push(KEY_NAME_MAP[cell]);
                    buff.push('</div></div>');
                } else {
                    buff.push('<div class="keypad_unit" style="visibility: hidden"></div>');
                }
            }
            buff.push('</div>');
        }
        keypad_div.innerHTML = buff.join('');

        function setKey(key, downOrUp){
            var str_key = '0x'+ ('00' + key.toString(16)).slice(-2);
            var keyUnit = document.querySelector('div.keypad_unit[data-key="' + str_key + '"]');
            if (keyUnit) {
                if (downOrUp) {
                    keyUnit.classList.add('pressed');
                } else {
                    keyUnit.classList.remove('pressed');
                }
            }
            wqx.setKey(key, downOrUp);
        }

        var last_mouse_down_key = null;
        keypad_div.addEventListener('mousedown', function (evt){
            var div = evt.target;
            do {
                if (div.classList.contains('keypad_unit')) {
                    var key = Number(div.getAttribute('data-key'));
                    last_mouse_down_key = key;
                    setKey(key, true);
                    break;
                }
                div = div.parentNode;
            } while (div && div.nodeType == 1);
        }, false);
        document.addEventListener('mouseup', function (evt){
            if (last_mouse_down_key != null) {
                if (!down_keys[last_mouse_down_key]) {
                    setKey(last_mouse_down_key, false);
                }
                last_mouse_down_key = null;
            }
        }, false);

        var down_keys = {};
        keypad_div.addEventListener('keydown', function (evt){
            if (KEY_CODE_MAP[evt.keyCode] != null) {
                var key = KEY_CODE_MAP[evt.keyCode];
                down_keys[key] = 1;
                setKey(key, true);
                evt.preventDefault();
            }
        });
        keypad_div.addEventListener('keyup', function (evt){
            if (KEY_CODE_MAP[evt.keyCode] != null) {
                var key = KEY_CODE_MAP[evt.keyCode];
                down_keys[key] = 0;
                setKey(key, false);
                evt.preventDefault();
            }
        });
    })();
function wqxDebugKey(key){
    wqx.setKey(key, true);
    setTimeout(function (){
        wqx.setKey(key, false);
    }, 20);
}
</script>
</body>
</html>